#!/bin/sh

e2e_test_install() {
  PROFILE="size-s"

  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1 \
    --set cluster.create=false --set cluster.sgInstanceProfile="$PROFILE"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  DEFAULT_PROFILE_CR="$(kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE" -o json \
    | jq 'del(.metadata.creationTimestamp) | del(.metadata.generation) | del(.metadata.resourceVersion) | del(.metadata.selfLink) | del(.metadata.uid)')"

  echo_raw "$DEFAULT_PROFILE_CR" > "$LOG_PATH/default-profile-cr.json"

  DEFALT_PROFILE="$(cat "$LOG_PATH/default-profile-cr.json" \
    | jq 'del(.apiVersion) | del(.kind)' )"

  echo_raw "$DEFALT_PROFILE" > "$LOG_PATH/default-profile.json"

  kubectl delete sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"
}

e2e_test_after_all() {
  unset PROFILE
}

e2e_test() {
  run_test "Check that a created profile can be accessed directly through the API" check_profile_directly

  run_test "Check that a created profile is included in the response" check_profile_in_list

  run_test "Check that a profile was removed from the list of profiles after its deletion" check_profile_removed_from_list

  run_test "Check that a profile was removed from direct access after its deletion" check_profile_deletion_directly

  run_test "Profile creation through the API" test_profile_create_with_api

  run_test "Check that a profile created with the API is visible" api_created_profile_visible

  run_test "Profile update with the api" test_update_profile_with_api

  run_test "Check that profile changes are reflected in the api" test_api_updated_profile_is_visible

  run_test "Check that profile deletions with the API are reflected in the API" test_api_delete_profile_is_invible

  run_test "Check profile deletion with api" test_delete_profile_with_api

  run_test "Deletion protected resources should not be deleted" test_dependency_api_error

  run_test "Constraint violations should be detected" test_constraint_violation_api_error

  run_test "User with wrong credentials should not be authenticated" test_authentication_api_error
}

create_profile() {
  kubectl apply -f "$LOG_PATH/default-profile-cr.json"

  wait_until eval 'kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"'
}

delete_profile_only() {
  echo "Deleting profile if there is any"
  if kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"
  then
    echo "Profile $PROFILE found, deleting..."

    kubectl delete sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"

    wait_until eval '! kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"'
  else
    echo "No profile found"
  fi
}

check_profile_in_list() {
  create_profile

  if run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\") | select ( .metadata.name == \"$PROFILE\") | .metadata.name" \
    | grep -q "^$PROFILE$"
  then
    echo "Profile $PROFILE included in json response"
    return 0
  else
    echo "Profile $PROFILE not included in json response"
    return 1
  fi
}

get_profile_status() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sginstanceprofiles/$PROFILE"  -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}"
}

check_profile_directly() {
  local HTTP_STATUS

  create_profile

  HTTP_STATUS="$(get_profile_status)"

  if [ "$HTTP_STATUS" -eq "200" ]
  then
    echo "Profile $PROFILE was found by the api"
    return 0
  else
    echo "Profile $PROFILE was not found by the api"
    return 1
  fi
}

check_profile_removed_from_list() {
  delete_profile_only

  if run_curl -r "stackgres/sginstanceprofiles"  -n "$CLUSTER_NAMESPACE" \
    | jq -r ".[] | select ( .metadata.namespace == \"$CLUSTER_NAMESPACE\") | select ( .metadata.name == \"$PROFILE\") | .metadata.name" \
    | grep -q "^$PROFILE$"
  then
    echo "Profile $PROFILE wasn't removed from cache";
    return 1
  else
    echo "Profile $PROFILE was removed from cache";
    return 0
  fi
}

check_profile_deletion_directly() {
  local HTTP_STATUS

  delete_profile_only

  HTTP_STATUS="$(run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sginstanceprofiles/$PROFILE" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  if [ "$HTTP_STATUS" -eq "404" ]
  then
    echo "Profile $PROFILE was not found by the api"
    return 0
  else
    echo "Profile $PROFILE was found by the api"
    return 1
  fi
}

create_profile_with_api() {
  echo "Creating profile $PROFILE with the operator API"

  delete_profile_only

  local HTTP_STATUS

  echo "Sending creation request"

  HTTP_STATUS="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X POST -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
  else
    local ERROR_RESPONSE
    ERROR_RESPONSE="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X POST')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_profile_create_with_api() {
  create_profile_with_api

  if wait_until eval 'kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"'
  then
    echo "Profile created with the operator API"
  else
    echo "Profile wasn't created with the API"
    return 1
  fi
}

api_created_profile_visible() {
  create_profile_with_api

  check_profile_directly
}

get_updated_profile() {
  UPDATED_PROFILE="$(cat "$LOG_PATH/default-profile.json" | jq ".spec[\"$1\"] = $2")"
  echo "$UPDATED_PROFILE"
}

update_profile_parameter_with_api() {
  local HTTP_STATUS

  write_to "$LOG_PATH/updated-profile.json" get_updated_profile "$1" "$2"

  HTTP_STATUS="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/updated-profile.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
  else
    local ERROR_RESPONSE
    ERROR_RESPONSE="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/updated-profile.json" -e '-X PUT')"

    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_update_profile_with_api() {
  create_profile

  update_profile_parameter_with_api 'memory' '"1Gi"'

  if kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE" -o jsonpath='{.spec.memory}' \
    | grep -q '^1Gi$'
  then
    echo "Profile was updated"
  else
    echo "Profile was not updated"
    return 1
  fi
}

get_profile_from_api() {
  run_curl -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sginstanceprofiles/$PROFILE" -n "$CLUSTER_NAMESPACE"
}

test_api_updated_profile_is_visible() {
  update_profile_parameter_with_api 'memory' '"1Gi"'

  if get_profile_from_api | jq '.spec.memory' -r \
    | grep -q '^1Gi$'
  then
    echo "Profile updates are being reflected in the api"
  else
    echo "Profile updates aren't being reflected in the api"
    return 1
  fi
}

delete_profile_with_api() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "202" ] || [ "$HTTP_STATUS" = "204" ]
  then
    echo "Request acknowledged by the operator"
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X PUT')"
    echo "Invalid response status $HTTP_STATUS. response: $ERROR_RESPONSE"
    return 1
  fi
}

test_delete_profile_with_api() {
  create_profile

  delete_profile_with_api

  if wait_until eval '! kubectl get sginstanceprofiles.stackgres.io -n "$CLUSTER_NAMESPACE" "$PROFILE"'
  then
    echo "Profile was deleted"
  else
    echo "Profile was not deleted"
    return 1
  fi
}

test_api_delete_profile_is_invible() {
  create_profile

  delete_profile_with_api

  if wait_until eval '[ "$(get_profile_status)" = "404" ]'
  then
    echo "Profile removed from the API"
  else
    echo "Profile wasn't removed from the API"
    return 1
  fi
}

test_constraint_violation_api_error() {
  PROFILE="$(get_updated_profile  'memory' '""')"

  echo "$PROFILE" > "$LOG_PATH/invalid-profile.json"

  HTTP_STATUS="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-profile.json" -e '-X POST -w %{http_code} -o /dev/null')"

  if [ "$HTTP_STATUS" = "422" ]
  then
    success "Operator api validated the profile"
  else
    ERROR_RESPONSE="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-profile.json" -e '-X POST')"
    fail "Status is not what is expected. HTTP_STATUS=$HTTP_STATUS. RESONSE:$ERROR_RESPONSE"
  fi

  ERROR_RESPONSE="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/invalid-profile.json" -e '-X POST')"

  EXPECTED_ERROR_TYPE="constraint-violation"
  EXPECTED_ERROR_TITLE="do not comply with the syntactic rules"
  EXPECTED_ERROR_DETAIL="spec.memory in body "
  EXPECTED_ERROR_FIELD="memory"

  assert_api_error "$ERROR_RESPONSE"
}

test_dependency_api_error(){
  remove_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"
  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1

  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  assert_string_equal "204" "$HTTP_STATUS"
}

test_authentication_api_error() {
  local HTTP_STATUS

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sginstanceprofiles"  -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/namespaces/$CLUSTER_NAMESPACE/sginstanceprofiles/$PROFILE" -n "$CLUSTER_NAMESPACE" -e "-LI -o /dev/null -w %{http_code}")"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X POST -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X PUT -w %{http_code} -o /dev/null')"

  check_authentication_error

  HTTP_STATUS="$(run_curl -j "$FAKE_JWT" -r "stackgres/sginstanceprofiles" -n "$CLUSTER_NAMESPACE" -d "$LOG_PATH/default-profile.json" -e '-X DELETE -w %{http_code} -o /dev/null')"

  check_authentication_error
}

check_authentication_error() {
  if [ "$HTTP_STATUS" = "401" ]
  then
    echo "Request returned expected authentication error"
    return 0
  else
    echo "Request returned unexpected response status $HTTP_STATUS instead of the expected authentication error."
    return 1
  fi
}